﻿using AutoMapper;
using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Contract.ContractMes;
using HamcoWcs.Contract.ContractPcon;
using HamcoWcs.Contract.ContractSrm;
using HamcoWcs.DAL;
using HamcoWcs.Entitys.Logss;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.TibcoMessage;
using HamcoWcs.Service.Common;
using HamcoWcs.Service.Mes;
using Microsoft.Extensions.Configuration;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;

namespace HamcoWcs.Workers.MESWokers
{
    /// <summary>MES消息处理后台服务</summary>
    [DisallowConcurrentExecution]
    public class MesWorker : WorkerBase
    {
        public override Task Execute(IJobExecutionContext context)
        {
            var state = _wcsDbContext.BaseConfigs.FirstOrDefault(x => x.ConfigKey == "WCSConnectState");
            if (state != null)
            {
                GlobalValue.WCSConnectState = state.ConfigValue == "1";
           
            }
            else
            {
                GlobalValue.WCSConnectState = false;
            }
            // WCS进入离线状态关闭MESWorker
            //if (!GlobalValue.WCSConnectState) return Task.CompletedTask;

            try
            {
                if (GlobalValue.MesInitFlag)
                {
                    DealLog();
                    //return Task.CompletedTask;
                    DealMesRequest();
                    DealWcsRequest();

                    if (GlobalValue.MesHBEnabled) HeartBeat();
                }
                else
                {
                    DoInit();
                }
            }
            catch (Exception e)
            {
                _logger.AddSystemErrorLog("MesWorker:" + e.Message);
            }
            return Task.CompletedTask;
        }

        /// <summary>已完成，异常存入日志</summary>
        private void DealLog()
        {
            var hbs = _wcsDbContext.MesMsgQueues
                                       .AsQueryable()
                                       .Where(x => x.EventName == "AreYouThereRequest")
                                       .Where(x => x.Status == (int)EnumMesMsgStatus.Completed
                                       || x.Status == (int)EnumMesMsgStatus.Closed
                                       || x.Status == (int)EnumMesMsgStatus.Error)
                                       .ToList();

            // 心跳信息直接存入Bak
            try
            {
                if (hbs != null || hbs.Count >= 0)
                {
                    var hblogs = hbs.Select(x => new HeartBeatLog()
                    {
                        TID = x.TransactionId,
                        ACK = true,
                        HBTarget = EnumHBTarget.MES,
                        HBTime = x.CreatedTime,
                        HBType = true
                    }).ToList();

                    _wcsDbContext.Set<HeartBeatLog>().AddRange(hblogs);
                    _wcsDbContext.RemoveRange(hbs);
                    _wcsDbContext.SaveChanges();
                    //var hbbaks = hbs.Select(x => new CommunicationLogBak()
                    //{
                    //    TransactionId = x.TransactionId,
                    //    Content = x.Content,
                    //    Return = x.Return,
                    //    Direction = x.Sender == 1 ? "WCS >> MES" : "WCS << MES",
                    //    MessageName = x.EventName,
                    //    MessageStatus = ((EnumMesMsgStatus)x.Status).ToString(),
                    //    MessageType = ((EnumMesRequestType)x.RequestType).ToString(),
                    //    UnitId = "",
                    //    Sender = x.Sender == 1 ? "WCS" : "MES",
                    //    Receiver = x.Sender == 1 ? "MES" : "WCS"
                    //}).ToList();

                    //_wcsDbContext.Set<CommunicationLogBak>().AddRange(hbbaks);
                    //_wcsDbContext.RemoveRange(hbs);
                    //_wcsDbContext.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                _logger.AddSystemErrorLog($"MesWorker->DealLog:备份心跳时未知异常\r\n{ex.Message}");
            }


            var mesmsgs = _wcsDbContext.MesMsgQueues
                                       .AsQueryable()
                                       .Where(x => x.Status == (int)EnumMesMsgStatus.Completed
                                       || x.Status == (int)EnumMesMsgStatus.Closed
                                       || x.Status == (int)EnumMesMsgStatus.Error)
                                       .ToList();

            if (mesmsgs == null || mesmsgs.Count == 0) return;


            try
            {
                var logs = mesmsgs.Select(x =>
                {
                    var unitId = XmlHelper.GetXPathText(x.Content, "//PALLETNAME");
                    if (string.IsNullOrEmpty(unitId))
                    {
                        unitId = XmlHelper.GetXPathText(x.Content, "//CARRIERNAME");
                    }

                    return new CommunicationLog()
                    {
                        TransactionId = x.TransactionId,
                        Content = x.Content,
                        Return = x.Return,
                        Direction = x.Sender == 1 ? "WCS >> MES" : "WCS << MES",
                        MessageName = x.EventName,
                        MessageStatus = ((EnumMesMsgStatus)x.Status).ToString(),
                        MessageType = ((EnumMesRequestType)x.RequestType).ToString(),
                        UnitId = unitId,
                        Sender = x.Sender == 1 ? "WCS" : "MES",
                        Receiver = x.Sender == 1 ? "MES" : "WCS"
                    };
                }).ToList();

                _wcsDbContext.Set<CommunicationLog>().AddRange(logs);
                _wcsDbContext.RemoveRange(mesmsgs);
                _wcsDbContext.SaveChanges();
            }
            catch (Exception ex)
            {
                _logger.AddSystemErrorLog($"MesWorker->DealLog:未知异常\r\n{ex.Message}");
            }
        }


        /// <summary>心跳</summary>
        private void HeartBeat()
        {
            GlobalValue.MesTimeTick++;
            if (GlobalValue.MesTimeTick < GlobalValue.MesHbInterval) return;

            GlobalValue.MesTimeTick = 0;
            // 队列中查找心跳信息
            var hb = _wcsDbContext.MesMsgQueues.FirstOrDefault(d => d.EventName.ToUpper() == "AREYOUTHEREREQUEST");

            if (hb != null)
            {
                if (hb.Status != (int)EnumMesMsgStatus.WcsWaitSend)
                {
                    hb.Return = "";
                    // 将心跳状态设置为等待发送
                    hb.Status = (int)EnumMesMsgStatus.WcsWaitSend;
                    // [2023-11-03] 新增日志
                    _logger.AddSystemErrorLog($"MesWorker->HeartBeat:[{hb.TransactionId}]{hb.Status}->WcsWaitSend");
                }

                // 没有收到MES回复时计数
                GlobalValue.MesConnectCount++;
                if (GlobalValue.MesConnectCount >= 3)
                {
                    // 持续3次未收到则MES设置为离线
                    GlobalValue.MesOnlineFlag = false;
                    // [2023-11-03] 新增日志
                    _logger.AddSystemErrorLog("MesWorker->HeartBeat:连续未收到MES回复心跳");
                    return;
                }
            }
            else
            {
                // 如果没找到,则表示连接成功，再次发送心跳
                GlobalValue.MesOnlineFlag = true;
                GlobalValue.MesConnectCount = 0;
                // AreYouThereRequest加入发送队列
                _mesCommunicateService.AreYouThereRequest();
            }

            _wcsDbContext.SaveChanges();
        }



        private void DealWcsRequest()
        {
            var mesmsgs = _wcsDbContext.MesMsgQueues
                                       .AsQueryable()
                                       .Where(x => x.Sender == (int)EnumMesMsgSender.WCS)
                                       .Where(x => x.RequestType == (int)EnumMesRequestType.Request)
                                       .Where(x => x.Status == (int)EnumMesMsgStatus.WcsReceived)
                                       .ToList();

            if (mesmsgs == null || mesmsgs.Count == 0) return;


            foreach (var msg in mesmsgs)
            {
                var parser = _mesMsgParserFactory.GetParser(msg.EventName);

                try
                {
                    if (parser == null) throw new ArgumentNullException(msg.EventName);
                    parser.HandleEvent(msg);
                }
                catch (ArgumentNullException ex)
                {
                    msg.Status = (int)EnumMesMsgStatus.Error;
                    _logger.AddSystemErrorLog($"MesWorker->DealMesRequest:未找到解析器 {ex.ParamName}");
                }
                catch (Exception ex)
                {
                    msg.Status = (int)EnumMesMsgStatus.Error;
                    _logger.AddSystemErrorLog($"MesWorker->DealMesRequest:未知异常\r\n{ex.Message}");
                }

            }
            _wcsDbContext.SaveChanges();
        }

        private void DealMesRequest()
        {
            var mesmsgs = _wcsDbContext.MesMsgQueues
                                       .AsQueryable()
                                       .Where(x => x.Sender == (int)EnumMesMsgSender.MES)
                                       .Where(x => x.RequestType == (int)EnumMesRequestType.Request)
                                       .Where(x => x.Status == (int)EnumMesMsgStatus.MesRequest
                                                   ||x.Status == (int)EnumMesMsgStatus.WcsWaitRecv)
                                       .ToList();

            if (mesmsgs == null || mesmsgs.Count == 0) return;
            foreach (var msg in mesmsgs)
            {
                //待测试
                //if (msg.Status == (int)EnumMesMsgStatus.WcsWaitRecv)
                //{
                //    GlobalValue.MesCount++;
                //    if (GlobalValue.MesCount == 30)
                //    {
                //        msg.Status = (int)EnumMesMsgStatus.WcsWaitSend;
                //        GlobalValue.MesCount = 0;
                //    }
                //}
                var parser = _mesMsgParserFactory.GetParser(msg.EventName);
                try
                {
                    if (parser == null) throw new ArgumentNullException(msg.EventName);
                    parser.HandleEvent(msg);
                    // parse
                }
                catch (ArgumentNullException ex)
                {
                    msg.Status = (int)EnumMesMsgStatus.Error;
                    _logger.AddSystemErrorLog($"MesWorker->DealMesRequest:未找到解析器 {ex.ParamName}");
                }
                catch (Exception ex)
                {
                    msg.Status = (int)EnumMesMsgStatus.Error;
                    _logger.AddSystemErrorLog($"MesWorker->DealMesRequest:未知异常\r\n{ex.Message}");
                }

            }
            _wcsDbContext.SaveChanges();
        }


        private void DoInit()
        {
            //GlobalValue.MesInitState = EnumMesInitState.None;
            //GlobalValue.MesInitState = EnumMesInitState.Finished;

            try
            {
                switch (GlobalValue.MesInitState)
                {
                    case EnumMesInitState.None: CreateConnection(); break;
                    case EnumMesInitState.Connecting: ConfirmConnection(); break;
                    case EnumMesInitState.Report: DoReport(); break;
                    case EnumMesInitState.Inventory: DoInventory(); break;
                    case EnumMesInitState.Finished:
                        _mesCommunicateService.SendBuffer();
                        _mesCommunicateService.CurrentStockerEmptyBoxPlanRequest("CJSTW100");
                        _mesCommunicateService.CurrentStockerEmptyBoxPlanRequest("CJSTW200");
                        GlobalValue.MesInitFlag = true;
                        break;
                }
                _wcsDbContext.SaveChanges();
            }
            catch (Exception ex)
            {
                _logger.AddSystemErrorLog("MesWorker Init Error:" + ex.Message);
            }

        }



        private void CreateConnection()
        {
            // [2024-01-23] ADD 重启时删除没用的上报信息，因为会再次发送这些信息
            var otherMsgs = _wcsDbContext.MesMsgQueues.Where(x => GlobalValue.MesOtherMsgNames.Contains(x.EventName)).ToList();
            _wcsDbContext.RemoveRange(otherMsgs);
            _wcsDbContext.SaveChanges();


            var msgs = _wcsDbContext.MesMsgQueues.Where(x => x.EventName == "AreYouThereRequest").ToList();

            if (msgs.Count > 0)
            {
                _wcsDbContext.MesMsgQueues.RemoveRange(msgs);
            }

            _mesCommunicateService.AreYouThereRequest();

            GlobalValue.MesInitState = EnumMesInitState.Connecting;
        }

        private void ConfirmConnection()
        {
            var messages = _wcsDbContext.MesMsgQueues
                                       .Where(x => x.EventName == "AreYouThereRequest")
                                       .ToList();

            if (messages.Count > 1)
            {
                _wcsDbContext.RemoveRange(messages);
                GlobalValue.MesInitState = EnumMesInitState.None;
            }
            else if (messages.Count == 1)
            {
                var message = messages.First();
                if (message.Status == (int)EnumMesMsgStatus.WcsReceived)
                {
                    message.Status = (int)EnumMesMsgStatus.Completed;
                    GlobalValue.MesOnlineFlag = true;
                    _monitorBaseService.MesMonitor.MesEnabled = 1;
                    GlobalValue.MesInitState = EnumMesInitState.Report;
                }
                else
                {
                    GlobalValue.MesTimeTick++;
                    if (GlobalValue.MesTimeTick >= 10)
                    {
                        GlobalValue.MesTimeTick = 0;
                        GlobalValue.MesConnectCount++;
                        message.Status = (int)EnumMesMsgStatus.WcsReSend;
                    }

                    if (GlobalValue.MesConnectCount >= 3)
                    {
                        GlobalValue.MesOnlineFlag = false;
                        message.Status = (int)EnumMesMsgStatus.WcsReSend;
                    }
                }
            }
            else
            {
                GlobalValue.MesInitState = EnumMesInitState.None;
            }
        }

        private void DoReport()
        {
            if (!GlobalValue.PconInitFlag) return;

            //var machines = _pconBaseService.GetMachines();
            var machines = _asrs.Nodes.Where(x => x.DeviceType == EnumNodeType.con);

            foreach (var machine in machines)
            {
                //machine.UpdateControlState();
                _mesCommunicateService.MachineControlStateChanged(machine);
            }

            foreach (var item in _asrs.Pcons.Where(x => x.PconType == EnumPconType.Wharf))
            {
                _mesCommunicateService.MachineModeChangeRequest(item, item.WorkType == 1 ? "IN" : "OUT");
            }

            Thread.Sleep(500);

            foreach (var machine in machines)
            {
                _mesCommunicateService.MachineStateChanged(machine);
            }

            Thread.Sleep(500);

            foreach (var machine in machines)
            {
                foreach (var port in machine.Pcons)
                {

                    _mesCommunicateService.PortStateChanged(port);
                    if (port.PconType == EnumPconType.OutPortInteractive)
                    {
                        if (port.IsGoods == 0 && port.PconMode == 1)
                        {
                            port.PortState = "LR";
                        }
                        else
                        {
                            port.PortState = "LC";
                        }
                        _mesCommunicateService.PortTransferStateChanged(port);
                    }
                    else if (port.PconType == EnumPconType.Wharf)
                    {
                        if (port.IsGoods == 0 && port.WorkType == 2 && port.PconMode == 1)
                        {
                            port.PortState = "UR";
                        }
                        else
                        {
                            port.PortState = "UC";
                        }
                        _mesCommunicateService.PortTransferStateChanged(port);
                    }
                }
            }

            GlobalValue.MesInitState = EnumMesInitState.Inventory;
        }

        private void DoInventory()
        {
            // 统计数量
            var zoneDic = _locationService.InventoryZonesByAisle();

            foreach (var aisle in zoneDic.Keys)
            {
                _mesCommunicateService.InventoryZoneDataRequest(new InventoryZoneDataReportMessage(new InventoryZoneDataReportMessageBody(aisle, zoneDic[aisle])));
            }

            var zonePallets = _locationService.InventoryPalletsByZone();

            foreach (var zoneName in zonePallets.Keys)
            {
                _mesCommunicateService.InventoryPalletDataRequest(new InventoryPalletDataReportMessage(new InventoryPalletDataReportMessageBody(zoneName.Substring(0, 8), zonePallets[zoneName])));
                Thread.Sleep(100);
            }


            //任务同步
            var maintasks = _wcsDbContext.MainTasks.ToList();
            if (maintasks.Count != 0)
                _mesCommunicateService.TransportJobListReportByWCS(maintasks);
            GlobalValue.MesInitState = EnumMesInitState.Finished;
        }

        #region [Constructor]



        private readonly IMesBaseService _mesBaseService;
        private readonly IMesCommunicateService _mesCommunicateService;
        private readonly ILocationService _locationService;
        private readonly IPconBaseService _pconBaseService;
        private readonly IBaseSrmTaskService _baseSrmTaskService;
        private readonly IMesMsgParserFactory _mesMsgParserFactory;
        private readonly IConfiguration _configuration;
        private readonly IMonitorBaseService _monitorBaseService;
        private readonly AutomaticStorageInfo _asrs;

        public MesWorker(IMapper mapper, WcsDbContext wcsDbContext, ILoggerService logger, IMesBaseService mesBaseService, IMesCommunicateService mesCommunicateService, ILocationService locationService, IPconBaseService pconBaseService, IMesMsgParserFactory mesMsgParserFactory, IConfiguration configuration, IBaseSrmTaskService baseSrmTaskService, IMonitorBaseService monitorBaseService, AutomaticStorageInfo asrs)
            : base(wcsDbContext, mapper, logger)
        {
            _mesBaseService = mesBaseService;
            _mesCommunicateService = mesCommunicateService;
            _locationService = locationService;
            _pconBaseService = pconBaseService;
            _mesMsgParserFactory = mesMsgParserFactory;
            _configuration = configuration;
            _baseSrmTaskService = baseSrmTaskService;

            var hBEnabled = _configuration["MesWork:HBEnabled"];
            var hbInterval = _configuration["MesWork:HBInterval"];

            GlobalValue.MesHBEnabled = hBEnabled == null ? true : hBEnabled.ToUpper() == "TRUE";
            GlobalValue.MesHbInterval = hbInterval == null ? 10 : int.Parse(hbInterval);
            _monitorBaseService = monitorBaseService;
            _asrs = asrs;
        }

        #endregion
    }
}
